package org.syncsoft.overalt.core.util;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Set;

import org.syncsoft.overalt.common.exception.SystemException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

/**
 * class that manipulates a XML file
 * it implements the singleton pattern
 * 
 * @author eajf 
 *
 */
public class XMLConfCore {

	private static XMLConfCore instance;

	public static XMLConfCore getInstance(){
		if(instance == null){
			instance = new XMLConfCore();
		}
		return instance;
	}

	private XMLConfCore(){

	}
	
	public String getFolderAutoFillTitleDescription(String folderPath) {
		return null;
	}

	public String getFolderAutoSync(String folderPath) {
		return null;
	}	

	/**
	 * Retrieve the folder Syncronization type by its path.
	 * 
	 * @param folderFilepath - The folder path
	 * @return the folder Syncronization type
	 * @throws SystemException
	 */
	public String getFolderTypeSyncronization(String folderFilepath)
	throws SystemException {
		String type = null;
		Document doc = getXML();
		NodeList nodes = doc.getElementsByTagName("folder");
		Element folder = XMLCore.getInstance().getFolder(folderFilepath, nodes);
		Element config = (Element)(folder.getElementsByTagName("config")).item(0);
		Element automatic = (Element)(config.getElementsByTagName("automatic")).item(0);
		if (automatic != null && automatic.getAttribute("auto").equals("true")) {
			type = automatic.getAttribute("type");
			if (folder != null) {
				return type;
			} else {
				throw new SystemException("The folder " + folderFilepath
						+ " doesn't exist.");
			}
		}else{
			throw new SystemException("There is no type Syncronization to the folder "+folderFilepath);
		}
	}
	
	

	/**
	 * Set if the folder is syncronized automatically, and if is, set the automatic type.
	 * 
	 * @param folderFilepath - The folder path
	 * @param isAuto - If this folder is syncronized automaticaly
	 * @throws SystemException
	 */
	public void setFolderAutomatic(String folderFilepath, boolean isAuto)
	throws SystemException {
		if(isAuto){
			throw new SystemException("To set this folder automatic you need to set the syncronization type too.");
		}
		Document doc = getXML();
		Element element = doc.createElement("automatic");
		element.setAttribute("auto", String.valueOf(isAuto));
		NodeList nodes = doc.getElementsByTagName("folder");
		Element temp = XMLCore.getInstance().getFolder(folderFilepath, nodes);
		NodeList folderNodes = temp.getElementsByTagName("config");
		Element config = getConfig(folderNodes);
		Element automatic = (Element) config.getElementsByTagName("automatic").item(0);
		if (temp != null) {
			if (automatic != null) {
				config.removeChild(automatic);
			}
			config.appendChild(element);
			setXML(doc);
		}else{
			throw new SystemException("The folder "+folderFilepath+" does't exist.");
		}
	}
	
	/**
	 * Set if the folder is syncronized automatically, and if is, set the automatic type.
	 * 
	 * @param folderFilepath - The folder path
	 * @param isAuto - If this folder is syncronized automaticaly
	 * @param type - The automatic type.
	 * @throws SystemException
	 */
	public void setFolderAutomatic(String folderFilepath, boolean isAuto, String type)
	throws SystemException {
		Document doc = getXML();
		Element element = doc.createElement("automatic");
		element.setAttribute("auto", String.valueOf(isAuto));
		if(isAuto && !type.trim().equals("")){
			element.setAttribute("type", type);
		}
		NodeList nodes = doc.getElementsByTagName("folder");
		Element temp = XMLCore.getInstance().getFolder(folderFilepath, nodes);
		NodeList folderNodes = temp.getElementsByTagName("config");
		Element config = getConfig(folderNodes);
		Element automatic = (Element) config.getElementsByTagName("automatic").item(0);
		if (temp != null) {
			if (automatic != null) {
				config.removeChild(automatic);
			}
			config.appendChild(element);
			setXML(doc);
		}else{
			throw new SystemException("The folder "+folderFilepath+" does't exist.");
		}
	}

	/**
	 * Retrieve all folders path that have an automatic syncronization
	 * 
	 * @return The collection of folders path
	 * @throws SystemException
	 */
	public Collection<String> getFoldersAutomatic()
	throws SystemException {
		Collection<String> folders = new ArrayList<String>();
		Document doc = getXML();
		NodeList nodes = doc.getElementsByTagName("folder");
		for (int i = 0; i < nodes.getLength(); i++) {
			Element config = (Element)(((Element)nodes.item(i)).getElementsByTagName("config")).item(0);
			Element automatic = (Element)(config.getElementsByTagName("automatic")).item(0);
			if(automatic != null && automatic.getAttribute("auto").equals("true")){
				folders.add(((Element)nodes.item(i)).getAttribute("path"));
			}
		}
		return folders;
	}

	/**
	 * Retrieve the folder share type by its path
	 * 
	 * @param folderFilepath - The folder path
	 * @return The folder share type
	 * @throws SystemException
	 */
	public String getFolderTypeShare(String folderFilepath)
	throws SystemException {
		Document doc = getXML();
		NodeList nodes = doc.getElementsByTagName("folder");
		Element folder = XMLCore.getInstance().getFolder(folderFilepath, nodes);
		return folder.getAttribute("typeShare");
	}

	/**
	 * Set the folder share type
	 * 
	 * @param folderFilepath - The folder path
	 * @param typeShare - The share type
	 * @throws SystemException
	 */
	public void setFolderTypeShare(String folderFilepath, String typeShare)
	throws SystemException {
		Document doc = getXML();
		NodeList nodes = doc.getElementsByTagName("folder");
		Element temp = XMLCore.getInstance().getFolder(folderFilepath, nodes);
		if(temp != null){
			temp.setAttribute("typeShare", String.valueOf(typeShare));
			setXML(doc);
		}else{
			throw new SystemException("The folder "+folderFilepath+" does't exist.");
		}
	}

	/**
	 * Retrieve the folder contacts by its path
	 * 
	 * @param folderFilepath - The folder path
	 * @return the Collection of Contacts id
	 * @throws SystemException
	 */
	public Collection<String> getFolderContacts(String folderFilepath)
	throws SystemException {
		Collection<String> contacts = new ArrayList<String>(); 
		Document doc = getXML();
		NodeList nodes = doc.getElementsByTagName("folder");
		Element folder = XMLCore.getInstance().getFolder(folderFilepath, nodes);
		NodeList folderNodes = folder.getElementsByTagName("config");
		Element config = getConfig(folderNodes);
		NodeList contactsNodes = config.getElementsByTagName("contact");
		for (int i = 0; i < contactsNodes.getLength(); i++) {
			Element contact = (Element)contactsNodes.item(i);
			if(contact != null){
				contacts.add(contact.getAttribute("id"));
			}
		}
		return contacts;
	}

	/**
	 * Retrieve the folder tags by its path
	 * 
	 * @param folderFilepath - The folder path
	 * @return The Collection of tags id
	 * @throws SystemException
	 */
	public Collection<String> getFolderTags(String folderFilepath)
	throws SystemException {
		Collection<String> tags = new ArrayList<String>(); 
		Document doc = getXML();
		NodeList nodes = doc.getElementsByTagName("folder");
		Element folder = XMLCore.getInstance().getFolder(folderFilepath, nodes);
		NodeList folderNodes = folder.getElementsByTagName("config");
		Element config = getConfig(folderNodes);
		NodeList tagsNodes = config.getElementsByTagName("tag");
		for (int i = 0; i < tagsNodes.getLength(); i++) {
			Element tag = (Element)tagsNodes.item(i);
			if (tag != null) {
				tags.add(tag.getAttribute("id"));
			}
		}
		return tags;
	}

	/**
	 * Add a community member into a folder
	 * 
	 * @param folderFilepath - The folder path
	 * @param memberId - The member id
	 * @throws SystemException
	 */
	public void setFolderMemberCommunity(String folderFilepath, String memberId)
	throws SystemException {
		Document doc = getXML();
		Element config = initFolderMembersTag(folderFilepath, doc);
		Element element = doc.createElement("member");
		element.setAttribute("id", memberId);
		NodeList nodes = config.getElementsByTagName("members");
		Element members = (Element)nodes.item(0);
		members.appendChild(element);
		setXML(doc);

	}

	/**
	 * Add a list of community members into a folder
	 * @param folderFilepath - The folder path
	 * @param membersId - The list of members id
	 * @throws SystemException
	 */
	public void setFolderMembersCommunity(String folderFilepath, List<String> membersId)
	throws SystemException {
		for (String memberId : membersId) {
			setFolderMemberCommunity(folderFilepath, memberId);
		}
	}

	/**
	 * Retrieve the folder community members from the folder path
	 * 
	 * @param folderFilepath - The folder path
	 * @return The collection of members id
	 * @throws SystemException
	 */
	public Collection<String> getFolderMembersCommunity(String folderFilepath)
	throws SystemException {
		Collection<String> members = new ArrayList<String>(); 
		Document doc = getXML();
		NodeList nodes = doc.getElementsByTagName("folder");
		Element folder = XMLCore.getInstance().getFolder(folderFilepath, nodes);
		NodeList folderNodes = folder.getElementsByTagName("config");
		Element config = getConfig(folderNodes);
		NodeList membersNodes = config.getElementsByTagName("member");
		for (int i = 0; i < membersNodes.getLength(); i++) {
			Element member = (Element)membersNodes.item(i); 
			if (member != null) {
				members.add(member.getAttribute("id"));
			}
		}
		return members;
	}

	/**
	 * Retrieve the default description of the user to commit an automatic file
	 * 
	 * @return The default description
	 * @throws SystemException
	 */
	public String getDefaultVersionDescription()
	throws SystemException {
		Document doc = getXML();
		return doc.getDocumentElement().getAttribute("defaultDescription");
	}

	/**
	 * Set a default description of the user to commit an automatic file
	 * 
	 * @param description - The default description
	 * @throws SystemException
	 */
	public void setDefaultVersionDescription(String description)
	throws SystemException {
		Document doc = getXML();
		Element root = doc.getDocumentElement();
		root.setAttribute("defaultDescription", description);
		setXML(doc);
	}

	/**
	 * Retrieve the Url server
	 * 
	 * @return The url server
	 * @throws SystemException
	 */
	public String getUrlServer()
	throws SystemException {
		Document doc = getXML();
		return doc.getDocumentElement().getAttribute("urlServer");
	}

	/**
	 * Set the Url server
	 * 
	 * @param urlServer - The url server
	 * @throws SystemException
	 */
	public void setUrlServer(String urlServer)
	throws SystemException {
		Document doc = getXML();
		Element root = doc.getDocumentElement();
		root.setAttribute("urlServer", urlServer);
		setXML(doc);
	}

	/**
	 * Retrieve the default permission of the files
	 * 
	 * @return the default permission
	 * @throws SystemException
	 */
	public String getDefaultPermission()
	throws SystemException {
		Document doc = getXML();
		return doc.getDocumentElement().getAttribute("defaultPermission");
	}

	/**
	 * Set the default permission of the files
	 * 
	 * @param defaultPermission - The default permission
	 * @throws SystemException
	 */
	public void setDefaultPermission(String defaultPermission)
	throws SystemException {
		Document doc = getXML();
		Element root = doc.getDocumentElement();
		root.setAttribute("defaultPermission", defaultPermission);
		setXML(doc);
	}

	/**
	 * Retrieve all folders path that have the title and description file filled automatically
	 * 
	 * @return the Collection of folders path
	 * @throws SystemException
	 */
	public Collection<String> getFoldersAutoTitleDescription()
	throws SystemException {
		Collection<String> folders = new ArrayList<String>();
		Document doc = getXML();
		NodeList nodes = doc.getElementsByTagName("folder");
		for (int i = 0; i < nodes.getLength(); i++) {
			Element tempFolder = (Element)nodes.item(i);
			if(tempFolder.getAttribute("autoTitleDescription").equals("true")){
				folders.add(((Element)nodes.item(i)).getAttribute("path"));
			}
		}
		return folders;
	}

	/**
	 * Set if the folder children have its title and description filled automatically
	 * 
	 * @param folderFilepath - The folder path
	 * @param isAuto - If have the title and description filled automatically
	 * @throws SystemException
	 */
	public void setFolderAutoTitleDescription(String folderFilepath, boolean isAuto)
	throws SystemException {
		Document doc = getXML();
		NodeList nodes = doc.getElementsByTagName("folder");
		Element temp = XMLCore.getInstance().getFolder(folderFilepath, nodes);
		if(temp != null){
			temp.setAttribute("autoTitleDescription", String.valueOf(isAuto));
			setXML(doc);
		}else{
			throw new SystemException("The folder "+folderFilepath+" does't exist.");
		}
	}

	/**
	 * Set the folder community
	 * 
	 * @param folderFilepath - The folder path
	 * @param communityId - The community id
	 * @throws SystemException
	 */
	public void setFolderCommunity(String folderFilepath, String communityId)
	throws SystemException {
		Document doc = getXML();
		Element element = doc.createElement("community");
		element.setAttribute("id", communityId);
		NodeList nodes = doc.getElementsByTagName("folder");
		Element tempFolder = XMLCore.getInstance().getFolder(folderFilepath, nodes);
		NodeList configNodes = tempFolder.getElementsByTagName("config");
		Element config = getConfig(configNodes);
		if(tempFolder != null){
			NodeList communityNodes = config.getElementsByTagName("community");
			if(communityNodes.getLength() == 0){
				config.appendChild(element);
			}else{
				Element temp = (Element)communityNodes.item(0);
				temp.setAttribute("id", communityId);
			}
			setXML(doc);
		}else{
			throw new SystemException("The folder "+folderFilepath+" doesn't exist.");
		}
	}

	/**
	 * Retrieve the folder community by its path
	 * 
	 * @param folderFilepath - The folder path
	 * @return the community id
	 * @throws SystemException
	 */
	public String getFolderCommunityByFolderFilepath(String folderFilepath)
	throws SystemException {
		String communityId = null;
		Document doc = getXML();
		NodeList nodes = doc.getElementsByTagName("folder");
		Element folder = XMLCore.getInstance().getFolder(folderFilepath, nodes);
		NodeList folderNodes = folder.getElementsByTagName("config");
		Element config = getConfig(folderNodes);
		NodeList configNodes = config.getElementsByTagName("community");
		for (int i = 0; i < configNodes.getLength(); i++) {
			communityId = ((Element)configNodes.item(i)).getAttribute("id");
		}

		if(folder != null){
			return communityId;
		}else{
			throw new SystemException("The folder "+folderFilepath+" doesn't exist.");
		}
	}

	/**
	 * Add a contact into a folder
	 * 
	 * @param folderFilepath - The folder path
	 * @param contactId - The contact id
	 * @throws SystemException
	 */
	public void addFolderContact(String folderFilepath, String contactId)
	throws SystemException {
		Document doc = getXML();
		Element config = initFolderContactsTag(folderFilepath, doc);
		Element element = doc.createElement("contact");
		element.setAttribute("id", contactId);
		NodeList nodes = config.getElementsByTagName("contacts");
		Element contacts = (Element)nodes.item(0);
		contacts.appendChild(element);
		setXML(doc);
	}

	/**
	 * Remove a contact from a folder
	 * 
	 * @param folderFilepath - The folder path
	 * @param contactId - The contact id
	 * @throws SystemException
	 */
	public void removeFolderContact(String folderFilepath, String contactId)
	throws SystemException {
		Document doc = getXML();
		NodeList nodes = doc.getElementsByTagName("folder");
		Element temp = XMLCore.getInstance().getFolder(folderFilepath, nodes);
		NodeList contactNodes = temp.getElementsByTagName("contact");
		Element contact = getElement(contactId, contactNodes);
		if(contact != null){
			contact.getParentNode().removeChild(contact);
			setXML(doc);
		}else{
			throw new SystemException("The contact id "+contactId+" doesn't exist.");
		}
	}

	/**
	 * Add a list of contacts into a folder
	 * 
	 * @param folderFilepath - The folder path
	 * @param contactsId - The list with all contacts id
	 * @throws SystemException
	 */
	public void addFolderContacts(String folderFilepath, List<String> contactsId)
	throws SystemException {
		for (String contactId : contactsId) {
			addFolderContact(folderFilepath, contactId);
		}
	}

	/**
	 * Remove all folder contacts
	 * 
	 * @param folderFilepath - The folder path
	 * @throws SystemException
	 */
	public void removeFolderContacts(String folderFilepath)
	throws SystemException {
		Document doc = getXML();
		NodeList folders = doc.getElementsByTagName("folder");
		NodeList contacts = null;
		Element temp = XMLCore.getInstance().getFolder(folderFilepath, folders);
		contacts = temp.getElementsByTagName("contact");
		if(contacts.getLength() > 0){
			for (int i = 0; i < contacts.getLength(); i++) {
				Element contact = (Element) contacts.item(i);
				removeFolderContact(folderFilepath, contact.getAttribute("id"));
			}
		}else{
			throw new SystemException("There are no contacts to the folder "+folderFilepath);
		}
	}

	/**
	 * Add a tag into a folder
	 * 
	 * @param folderFilepath - The folder path
	 * @param tagId - The tag id
	 * @throws SystemException
	 */
	public void addFolderTag(String folderFilepath, String tagId)
	throws SystemException {
		Document doc = getXML();
		Element config = initFolderTagsTag(folderFilepath, doc);
		Element element = doc.createElement("tag");
		element.setAttribute("id", tagId);
		Element tags = null;
		NodeList nodes = config.getElementsByTagName("tags");
		tags = (Element)nodes.item(0);
		tags.appendChild(element);
		setXML(doc);
	}

	/**
	 * Remove a tag from a folder
	 * 
	 * @param folderFilepath - The folder path
	 * @param tagId - The tag id
	 * @throws SystemException
	 */
	public void removeFolderTag(String folderFilepath, String tagId)
	throws SystemException {
		Document doc = getXML();
		NodeList nodes = doc.getElementsByTagName("folder");
		Element temp = XMLCore.getInstance().getFolder(folderFilepath, nodes);
		NodeList tagNodes = temp.getElementsByTagName("tag");
		Element tag = getElement(tagId, tagNodes);
		if(tag != null){
			tag.getParentNode().removeChild(tag);
			setXML(doc);
		}else{
			throw new SystemException("The tag id "+tagId+" doesn't exist.");
		}
	}

	/**
	 * Add a list of tags into a folder
	 * 
	 * @param folderFilepath - The folder path
	 * @param tagsId - The list with all tags id 
	 * @throws SystemException
	 */
	public void addFolderTags(String folderFilepath, List<String> tagsId)
	throws SystemException {
		for (String tagId : tagsId) {
			addFolderTag(folderFilepath, tagId);
		}
	}

	/**
	 * Remove all folder tags by its path
	 * 
	 * @param folderFilepath - The folder path
	 * @throws SystemException
	 */
	public void removeFolderTags(String folderFilepath)
	throws SystemException {
		Document doc = getXML();
		NodeList folders = doc.getElementsByTagName("folder");
		NodeList tags = null;
		Element temp = XMLCore.getInstance().getFolder(folderFilepath, folders);
		tags = temp.getElementsByTagName("tag");
		if(tags.getLength() > 0){
			for (int i = 0; i < tags.getLength(); i++) {
				Element tag = (Element) tags.item(i);
				removeFolderTag(folderFilepath, tag.getAttribute("id"));
			}
		}else{
			throw new SystemException("There are no tags to the folder "+folderFilepath);
		}
	}

	/**
	 * Initialize the tags tag into a folder and return its config
	 * 
	 * @param folderFilepath - The folder path
	 * @param doc - The Document objetct
	 * @return the Config element
	 * @throws SystemException
	 */
	private Element initFolderTagsTag(String folderFilepath, Document doc)
	throws SystemException {
		Element element = doc.createElement("tags");
		NodeList nodes = doc.getElementsByTagName("folder");
		Element folder = XMLCore.getInstance().getFolder(folderFilepath, nodes);
		NodeList configNodes = folder.getElementsByTagName("config");
		Element config = getConfig(configNodes);
		if (folder != null) {
			if (config.getElementsByTagName("tags").getLength() == 0) {
				config.appendChild(element);
			}
		}else{
			throw new SystemException("The folder "+folderFilepath+" doesn't exist.");
		}
		return config;
	}

	/**
	 * Initialize the contacts tag into a folder and return its config
	 * 
	 * @param folderFilepath - The folder path
	 * @param doc - The Document objetc
	 * @return the Config element
	 * @throws SystemException
	 */
	private Element initFolderContactsTag(String folderFilepath, Document doc)
	throws SystemException {
		Element element = doc.createElement("contacts");
		NodeList nodes = doc.getElementsByTagName("folder");
		Element folder = XMLCore.getInstance().getFolder(folderFilepath, nodes);
		NodeList configNodes = folder.getElementsByTagName("config");
		Element config = getConfig(configNodes);
		if (folder != null) {
			if (config.getElementsByTagName("contacts").getLength() == 0) {
				config.appendChild(element);
			}
		}else{
			throw new SystemException("The folder "+folderFilepath+" doesn't exist.");
		}
		return config;
	}

	/**
	 * Initialize the members tag into a folder and return its config
	 * 
	 * @param folderFilepath - The folder path
	 * @param doc - The Document object
	 * @return the Config element
	 * @throws SystemException
	 */
	private Element initFolderMembersTag(String folderFilepath, Document doc)
	throws SystemException {
		Element element = doc.createElement("members");
		NodeList nodes = doc.getElementsByTagName("folder");
		Element folder = XMLCore.getInstance().getFolder(folderFilepath, nodes);
		NodeList configNodes = folder.getElementsByTagName("config");
		Element config = getConfig(configNodes);
		if (folder != null) {
			if (config.getElementsByTagName("members").getLength() == 0) {
				config.appendChild(element);
			}
		}else{
			throw new SystemException("The folder "+folderFilepath+" doesn't exist.");
		}
		return config;
	}

	/**
	 * Initialize the tags tag into a file and return its file
	 * 
	 * @param fileId - The file id
	 * @param doc - the Document object
	 * @return the File element
	 * @throws SystemException
	 */
	private Element initFileTagsTag(String fileId, Document doc)
	throws SystemException {
		Element element = doc.createElement("tags");
		NodeList nodes = doc.getElementsByTagName("file");
		Element file = XMLCore.getInstance().getFileById(fileId, nodes);
		if (file != null) {
			if (file.getElementsByTagName("tags").getLength() == 0) {
				file.appendChild(element);
			}
		}else{
			throw new SystemException("The file id "+fileId+" doesn't exist.");
		}
		return file;
	}

	/**
	 * Initialize the communities tag into a file and return its file
	 * 
	 * @param fileId - The file id
	 * @param doc - The Document object
	 * @return the File element
	 * @throws SystemException
	 */
	private Element initFileCommunitiesTag(String fileId, Document doc)
	throws SystemException {
		Element element = doc.createElement("communities");
		NodeList nodes = doc.getElementsByTagName("file");
		Element file = XMLCore.getInstance().getFileById(fileId, nodes);
		if (file != null) {
			if (file.getElementsByTagName("communities").getLength() == 0) {
				file.appendChild(element);
			}
		}else{
			throw new SystemException("The file id "+fileId+" doesn't exist.");
		}
		return file;
	}

	/**
	 * Retrieve the syncronization time
	 * 
	 * @return the syncronization time
	 * @throws SystemException
	 */
	public int getTimeSync()
	throws SystemException{
		Document doc = getXML();
		Element root = doc.getDocumentElement();
		return Integer.parseInt(root.getAttribute("time"));
	}

	/**
	 * Set the syncronization time
	 * 
	 * @param time - the syncronization time
	 * @throws SystemException
	 */
	public void setTimeSync(String time)
	throws SystemException {
		Document doc = getXML();
		Element root = doc.getDocumentElement();
		root.setAttribute("time", time);
		setXML(doc);
	}

	/**
	 * Retrieve the Config element
	 * 
	 * @param folderNodes - A list of configs
	 * @return the Config element
	 */
	private Element getConfig(NodeList folderNodes) {
		Element config = null;
		for(int j = 0; j < folderNodes.getLength(); j++){
			config = (Element) folderNodes.item(j); 
		}
		return config;
	}

	/**
	 * Retrieve an element by its id
	 * 
	 * @param id - the element id
	 * @param nodes - the list with the elements with the same type
	 * @return the Element
	 */
	private Element getElement(String id, NodeList nodes) {
		Element element = null;
		for (int l = 0; l < nodes.getLength(); l++) {
			Element aux = (Element) nodes.item(l);
			if(aux.getAttribute("id").equals(id)){
				element = aux;
				break;
			}
		}
		return element;
	}

	/**
	 * Retrieve an Element
	 * 
	 * @param nodes - The list with only one element
	 * @return the Element
	 */
	private Element getElement(NodeList nodes) {
		Element element = null;
		for (int i = 0; i < nodes.getLength(); i++) {
			element = (Element) nodes.item(i);
		}
		return element;
	}

	/**
	 * Set the file communities by its id
	 * 
	 * @param communitiesId - The set of the communities id
	 * @param fileId - The file id
	 * @throws SystemException
	 */
	public void setFileCommunities(Set<String> communitiesId, String fileId)
	throws SystemException {
		for (String communityId : communitiesId) {
			addFileCommunity(communityId, fileId);
		}
	}

	/**
	 * Retrieve a collection of file communities id
	 * 
	 * @param fileId - The file id
	 * @return the collection of communities id
	 * @throws SystemException
	 */
	public Collection<String> getFileCommunities(String fileId)
	throws SystemException {
		Collection<String> communities = new ArrayList<String>(); 
		Document doc = getXML();
		NodeList nodes = doc.getElementsByTagName("file");
		Element file = XMLCore.getInstance().getFileById(fileId, nodes);
		NodeList fileNodes = file.getElementsByTagName("communities");
		Element fileCommunities = getElement(fileNodes);
		if (fileCommunities != null) {
			NodeList communitiesNodes = fileCommunities
					.getElementsByTagName("community");
			for (int i = 0; i < communitiesNodes.getLength(); i++) {
				Element community = (Element) communitiesNodes.item(i);
				if (community != null) {
					communities.add(community.getAttribute("id"));
				}
			}
		}
		return communities;
	}

	/**
	 * Set the file tags by its id
	 * 
	 * @param tagsId - The set of tags id
	 * @param fileId - The file id
	 * @throws SystemException
	 */
	public void setFileTags(Set<String> tagsId, String fileId)
	throws SystemException {
		for (String tagId : tagsId) {
			addFileTag(tagId, fileId);
		}
	}

	/**
	 * Retrieve a collection of file tags by its id
	 * 
	 * @param fileId - The file id
	 * @return the collection of tags id
	 * @throws SystemException
	 */
	public Collection<String> getFileTags(String fileId)
	throws SystemException {
		Collection<String> tags = new ArrayList<String>(); 
		Document doc = getXML();
		NodeList nodes = doc.getElementsByTagName("file");
		Element file = XMLCore.getInstance().getFileById(fileId, nodes);
		NodeList fileNodes = file.getElementsByTagName("tags");
		Element fileTags = getElement(fileNodes);
		if (fileTags != null) {
			NodeList tagsNodes = fileTags.getElementsByTagName("tag");
			for (int i = 0; i < tagsNodes.getLength(); i++) {
				tags.add(((Element) tagsNodes.item(i)).getAttribute("id"));
			}
		}
		return tags;
	}

	/**
	 * Set the file permission
	 * 
	 * @param permission - The permission type
	 * @param fileId - The File id
	 * @throws SystemException
	 */
	public void setFilePermission(String permission, String fileId)
	throws SystemException {
		Document doc = getXML();
		NodeList nodes = doc.getElementsByTagName("file");
		Element file = XMLCore.getInstance().getFileById(fileId, nodes);
		if (file != null) {
			file.setAttribute("permission", permission);
			setXML(doc);
		}
	}

	/**
	 * Retrieve the file permission by its id
	 * 
	 * @param fileId - The file id
	 * @return the permission type
	 * @throws SystemException
	 */
	public int getFilePermission(String fileId)
	throws SystemException {
		Document doc = getXML();
		NodeList nodes = doc.getElementsByTagName("file");
		Element file = XMLCore.getInstance().getFileById(fileId, nodes);
		return Integer.parseInt(file.getAttribute("permission"));

	}

	/**
	 * Add a community into a file
	 * 
	 * @param communityId - The community id
	 * @param fileId - The file id
	 * @throws SystemException
	 */
	public void addFileCommunity(String communityId, String fileId)
	throws SystemException {
		Document doc = getXML();
		Element file = initFileCommunitiesTag(fileId, doc);
		Element element = doc.createElement("community");
		element.setAttribute("id", communityId);
		Element communities = null;
		NodeList nodes = file.getElementsByTagName("communities");
		communities = (Element)nodes.item(0);
		if (!communityExists(communityId, fileId)) {
			communities.appendChild(element);
			setXML(doc);
		}
	}

	/**
	 * Verify if a community id exists to this file id
	 * 
	 * @param communityId - The community id
	 * @param fileId - The file id
	 * @return true if the community exists
	 * @throws SystemException
	 */
	private boolean communityExists(String communityId, String fileId)
	throws SystemException {
		 Collection<String> communities = getFileCommunities(fileId);
		 boolean exists = communities.contains(communityId);
		return exists;
	}
	
	/**
	 * Verify if a tag id exists to this file id
	 * 
	 * @param tagId - The tag id
	 * @param fileId - The file id
	 * @return true if the tag exists
	 * @throws SystemException
	 */
	private boolean tagExists(String tagId, String fileId)
	throws SystemException {
		 Collection<String> tags = getFileTags(fileId);
		 boolean exists = tags.contains(tagId);
		return exists;
	}

	/**
	 * Add a tag into a file
	 * 
	 * @param tagId - The tag id 
	 * @param fileId - The file id
	 * @throws SystemException
	 */
	public void addFileTag(String tagId, String fileId)
	throws SystemException {
		Document doc = getXML();
		Element file = initFileTagsTag(fileId, doc);
		Element element = doc.createElement("tag");
		element.setAttribute("id", tagId);
		Element tags = null;
		NodeList nodes = file.getElementsByTagName("tags");
		tags = (Element)nodes.item(0);
		if (!tagExists(tagId, fileId)) {
			tags.appendChild(element);
			setXML(doc);
		}
	}

	/**
	 * Set the file title
	 * 
	 * @param fileId - The file id
	 * @param title - The file title
	 * @throws SystemException
	 */
	public void setFileTitle(String fileId, String title)
	throws SystemException {
		Document doc = getXML();
		NodeList nodes = doc.getElementsByTagName("file");
		Element file = XMLCore.getInstance().getFileById(fileId, nodes);
		if (file != null) {
			file.setAttribute("title", title);
			setXML(doc);
		}
	}

	/**
	 * Set the file description
	 * 
	 * @param fileId - The file id
	 * @param description - The file description
	 * @throws SystemException
	 */
	public void setFileDescription(String fileId, String description)
	throws SystemException {
		Document doc = getXML();
		NodeList nodes = doc.getElementsByTagName("file");
		Element file = XMLCore.getInstance().getFileById(fileId, nodes);
		if (file != null) {
			file.setAttribute("description", description);
			setXML(doc);
		}
	}

	/**
	 * Retrieve the file title
	 * 
	 * @param fileId - The file id
	 * @return the file title
	 * @throws SystemException
	 */
	public String getFileTitle(String fileId)
	throws SystemException {
		Document doc = getXML();
		NodeList nodes = doc.getElementsByTagName("file");
		Element file = XMLCore.getInstance().getFileById(fileId, nodes);
		return file.getAttribute("title");
	}

	/**
	 * Retrieve the file description
	 * 
	 * @param fileId - The file id
	 * @return the file description
	 * @throws SystemException
	 */
	public String getFileDescription(String fileId)
	throws SystemException {
		Document doc = getXML();
		NodeList nodes = doc.getElementsByTagName("file");
		Element file = XMLCore.getInstance().getFileById(fileId, nodes);
		return file.getAttribute("description");
	}

	/**
	 * Retrieve the last file modified date
	 * 
	 * @param fileId - the File id
	 * @return the Last Modified date
	 * @throws SystemException
	 */
	public String getLastModified(String fileId)
	throws SystemException {
		Document doc = getXML();
		NodeList nodes = doc.getElementsByTagName("file");
		Element file = XMLCore.getInstance().getFileById(fileId, nodes);
		if(file != null){
			return file.getAttribute("lastModified");
		}else{
			throw new SystemException("The file id "+fileId+" doesn't exist.");
		}

	}

	/**
	 * Set the last file modified date
	 * 
	 * @param fileId - The file id
	 * @param lastModified - The last modified date
	 * @throws SystemException
	 */
	public void setLastModified(String fileId, String lastModified)
	throws SystemException {
		Document doc = getXML();
		NodeList nodes = doc.getElementsByTagName("file");
		Element file = XMLCore.getInstance().getFileById(fileId, nodes);
		if (file != null) {
			file.setAttribute("lastModified", lastModified);
			setXML(doc);
		}else{
			throw new SystemException("The file id "+fileId+" doesn't exist.");
		}

	}

	/**
	 * Retrieve the user XML mapped on memory
	 * 
	 * @return the XML Document object
	 * @throws SystemException
	 */
	private Document getXML()
	throws SystemException {
		return XMLCore.getInstance().getXML();
	}

	/**
	 * Save the XML that have been modified on memory on the XML file
	 * 
	 * @param doc - The XML Document object
	 * @throws SystemException
	 */
	private void setXML(Document doc)
	throws SystemException {
		XMLCore.getInstance().setXML(doc);
	}

}
